import ExcelJS from "exceljs";
import * as XLSX from "xlsx";
import $common from "@/utils/$common";

export async function outExcel({
  filename,
  header,
  table,
  option = {},
  before,
}) {
  // 创建excel
  const workbook = new ExcelJS.Workbook();
  // 设置信息
  let currentTime = new Date();
  workbook.creator = "";
  workbook.title = filename;
  workbook.created = currentTime;
  workbook.modified = currentTime;

  let c = {
    rowHeight: 30, //默认行高
    border: false, //是否需要边框

    headerStyle: {
      fill: {
        type: "pattern",
        pattern: "solid",
        fgColor: { argb: "fff6f8fa" },
      },
      border: {
        top: { style: "thin", color: { argb: "ffd0d7de" } },
        left: { style: "thin", color: { argb: "ffd0d7de" } },
        bottom: { style: "thin", color: { argb: "ffd0d7de" } },
        right: { style: "thin", color: { argb: "ffd0d7de" } },
      },
    },

    //大标题
    title: "", //是否需要一级标题
    titleStyle: {
      font: {
        size: 18,
      },
      fill: {
        type: "pattern",
        pattern: "solid",
        fgColor: { argb: "fff6f8fa" },
      },
      border: {
        top: { style: "thin", color: { argb: "ffd0d7de" } },
        left: { style: "thin", color: { argb: "ffd0d7de" } },
        bottom: { style: "thin", color: { argb: "ffd0d7de" } },
        right: { style: "thin", color: { argb: "ffd0d7de" } },
      },
    },
  };
  let config = { ...c, ...option };

  //创建一个工作表
  const worksheet = workbook.addWorksheet(filename);
  worksheet.properties.defaultRowHeight = config.rowHeight; //默认行高

  let columns = [];
  let handleImageList = []; //需要处理的图片对象
  let handleImageTotal = 0; //需要处理的图片总数
  let handleImageIndex = 0;
  let handleImageMerge = [];

  let headerList = $common.deepCopy(header); //表头
  let tableList = $common.deepCopy(table); //表格

  headerList.forEach((item) => {
    if (item.type == "image") {
      tableList.forEach((self) => {
        let arr = self[item.key];
        handleImageTotal += arr.length;
        if (arr && arr.length) {
          handleImageList.push({
            data: arr,
            self,
            key: item.key,
          });
        }
      });
      handleImageMerge.push({
        start: handleImageIndex + 1,
        end: handleImageIndex + item.max,
      });

      handleImageIndex += item.max;
    } else {
      handleImageIndex++;
    }
  });

  await handleImage(handleImageList, handleImageTotal);

  headerList.forEach((item, index) => {
    //处理图片
    if (item.type == "image") {
      let max = item?.max || 1;
      for (let i = 0; i < max; i++) {
        let obj = {
          ...item,
          header: item.title,
          width: item.width || item.title.length * 5 || 20,
          key: item.key + "" + i,
        };
        tableList.forEach((self, current) => {
          self[item.key + "" + i] = self[item.key][i] || "";
        });
        columns.push(obj);
      }

      return;
    }

    //处理下拉数据
    if (item.type == "select") {
      //选择的下拉数据将从生成新的sheet表A列中获取
      const sheet = workbook.addWorksheet(item.title);
      sheet.getColumn(1).values = item.selectList;
      item.formulae = [`${item.title}!$A$1:$A$${item.selectList.length}`];
      // item.formulae=[`"${item.selectList.join(",")}"`]; (此方法不能导出过长的选择列表)
    }

    let obj = {
      ...item,
      header: item.title,
      width: item.width || item.title.length * 5 || 20,
      key: item.key,
    };

    columns.push(obj);
  });
  // console.log(columns);
  // console.log(tableList);

  worksheet.columns = columns;

  // 设置表数据
  tableList.forEach((x) => {
    worksheet.addRow(x);
  });
  let maxRow = tableList.length + 1;
  // 设置可编辑最大行数，用来显示下拉单元格
  if (tableList.length < 100) {
    worksheet.getRow(100);
    maxRow = 100;
  }

  let insertTitleIndex = 0;
  //如果存在大标题
  if (config.title) {
    let titleRow = worksheet.insertRow(1);
    titleRow.values = [config.title];
    worksheet.mergeCells(1, 1, 1, columns.length);
    insertTitleIndex = 1;
  }

  //遍历每列每行的数据
  columns.forEach((item, current) => {
    worksheet
      .getColumn(item.key)
      .eachCell({ includeEmpty: true }, function (cell, rowNumber) {
        //rowNumber 从1开始
        let tableRowData = tableList[rowNumber - 2 - insertTitleIndex];
        //过滤表头第一行数据
        if (rowNumber > insertTitleIndex + 1) {
          if (item.type == "select") {
            cell.dataValidation = {
              type: "list",
              allowBlank: false,
              formulae: item.formulae,
              operator: "notEqual",
              showErrorMessage: true,
              errorStyle: "error",
              errorTitle: "错误提示",
              error: "您输入的内容，不符合限制条件",
            };
          }
          if (item.type == "image") {
            if (tableRowData && tableRowData[item.key]) {
              let imageId = workbook.addImage({
                base64: tableRowData[item.key],
              });
              worksheet.addImage(imageId, {
                tl: { col: current, row: rowNumber - 1 },
                br: { col: current + 1, row: rowNumber },
              });
              cell.value = "";
            }
          }
        }

        cell.alignment = {
          vertical: "middle",
          horizontal: "center",
          wrapText: true,
        };
      });
  });

  for (let i = 1; i <= maxRow; i++) {
    worksheet.getRow(i).eachCell({ includeEmpty: true }, function (cell, b) {
      if (config.border) {
        cell.border = {
          top: { style: "thin" },
          left: { style: "thin" },
          bottom: { style: "thin" },
          right: { style: "thin" },
        };
      }
      //设置title样式
      if (i == insertTitleIndex) {
        for (let key in config.titleStyle) {
          cell[key] = config.titleStyle[key];
        }
      }

      //设置header样式
      if (i == 1 + insertTitleIndex) {
        for (let key in config.headerStyle) {
          cell[key] = config.headerStyle[key];
        }
      }
    });

    handleImageMerge.forEach((item) => {
      worksheet.mergeCells(
        i + insertTitleIndex,
        item.start,
        i + insertTitleIndex,
        item.end
      );
    });
  }

  if (before) {
    before(worksheet, next);
  } else {
    next();
  }

  function next() {
    workbook.xlsx.writeBuffer().then((data) => {
      const blob = new Blob([data, { type: "application/vnd.ms-excel" }]);
      if (window.navigator.msSaveOrOpenBlob) {
        navigator.msSaveBlob(blob, filename + ".xlsx");
        // 本地保存
      } else {
        const link = document.createElement("a"); // a标签下载
        link.href = window.URL.createObjectURL(blob); // href属性指定下载链接
        link.download = filename + ".xlsx"; // dowload属性指定文件名
        link.click(); // click()事件触发下载
        window.URL.revokeObjectURL(link.href); // 释放内存
      }
    });
  }
}

//处理图片,将图片转换为base64
function handleImage(list, total) {
  let num = 0;
  return new Promise((resolve) => {
    list.forEach((item) => {
      item.data.forEach((url, current) => {
        $common
          .loadImage(url)
          .then((res) => {
            let base64 = $common.imageDomToBase64(res);
            item.self[item.key][current] = base64;
          })
          .catch((err) => {
            console.log("该图片转换失败", url, err);
            item.self[item.key][current] = "";
          })
          .finally(() => {
            num++;
            if (num == total) {
              resolve();
            }
          });
      });
    });
  });
}

//读取execl文件
export function readExcel(columsList) {
  //columsList=['name','phone']
  if (!columsList || !columsList.length) {
    console.log("请传入表单每列key值");
    return;
  }
  return new Promise((resolve, reject) => {
    let input = document.createElement("input");
    input.type = "file";
    input.addEventListener("change", inputFn);
    input.click();
    input.remove();

    function inputFn() {
      let reader = new FileReader();
      reader.readAsBinaryString(input.files[0]);
      reader.onload = function (e) {
        const data = e.target.result;
        const workbook = XLSX.read(data, { type: "binary" });

        const sheetsObj = workbook.Sheets[workbook.SheetNames[0]];
        const excelDataArr = XLSX.utils.sheet_to_json(sheetsObj, {
          header: columsList,
        });
        resolve(excelDataArr);
      };
      reader.onerror = function (e) {
        reject(e);
      };
    }
  });
}
